﻿using System.ComponentModel;
using System.Reflection;

namespace Luka;

/// <summary>
/// 枚举拓展类
/// </summary>
public static class EnumExtensions
{
    /// <summary>
    /// 获取枚举值的描述
    /// </summary>
    public static string GetDescription<TEnum>(this TEnum value) where TEnum : struct, Enum
    {
        return GetDescription(value, typeof(TEnum));
    }

    /// <summary>
    /// 获取枚举值的描述
    /// </summary>
    public static string GetDescription(this Enum value, Type enumType)
    {
        // 检查是否是枚举类型
        if (!enumType.IsEnum)
        {
            throw new ArgumentException("The parameter is not an enum type.", nameof(value));
        }

        // 判断是否有效
        if (!Enum.IsDefined(enumType, value))
        {
            throw new ArgumentNullException(nameof(value), "传入的枚举值为空");
        }

        // 获取枚举名称
        var enumName = Enum.GetName(enumType, value);

        // 空检查
        ArgumentNullException.ThrowIfNull(enumName);

        // 获取枚举字段
        var enumField = enumType.GetField(enumName);

        // 空检查
        ArgumentNullException.ThrowIfNull(enumField);

        // 获取 [Description] 特性描述
        return enumField.GetCustomAttribute<DescriptionAttribute>(false)?.Description ?? enumName;
    }

    /// <summary>
    /// 将枚举转成枚举信息集合
    /// </summary>
    public static List<EnumItem<int>> EnumToList(this Type enumType)
    {
        return enumType.EnumToList<int>();
    }

    /// <summary>
    /// 将枚举转成枚举信息集合
    /// </summary>
    public static List<EnumItem<TProperty>> EnumToList<TProperty>(this Type enumType) where TProperty : struct, IComparable, IConvertible, IFormattable
    {
        if (!enumType.IsEnum)
            throw new ArgumentException("Type '" + enumType.Name + "' is not an enum.", nameof(enumType));

        var propertyType = typeof(TProperty);

        return Enum.GetValues(enumType).Cast<Enum>().Select(enumValue => new EnumItem<TProperty>
        {
            Name = enumValue.ToString(),
            Describe = enumValue.GetDescription(enumType),
            Value = (TProperty)Convert.ChangeType(enumValue, propertyType)
        }).ToList();
    }
}

/// <summary>
/// 枚举项
/// </summary>
public class EnumItem<TProperty> where TProperty : struct, IComparable, IConvertible, IFormattable
{
    /// <summary>  
    /// 枚举的描述  
    /// </summary>  
    public string? Describe { set; get; }

    /// <summary>  
    /// 枚举名称  
    /// </summary>  
    public string? Name { set; get; }

    /// <summary>  
    /// 枚举对象的值  
    /// </summary>  
    public TProperty Value { set; get; }
}